﻿/*********************************************************************************
**                                                                              **
**  Copyright (C) 2024 LiLong                                                   **
**  This file is part of GnssLogs.                                              **
**                                                                              **
**  GnssLogs is free software: you can redistribute it and/or modify            **
**  it under the terms of the GNU Lesser General Public License as published by **
**  the Free Software Foundation, either version 3 of the License, or           **
**  (at your option) any later version.                                         **
**                                                                              **
**  GnssLogs is distributed in the hope that it will be useful,                 **
**  but WITHOUT ANY WARRANTY; without even the implied warranty of              **
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               **
**  GNU Lesser General Public License for more details.                         **
**                                                                              **
**  You should have received a copy of the GNU Lesser General Public License    **
**  along with GnssLogs.  If not, see <https://www.gnu.org/licenses/>.          **
**********************************************************************************/
#pragma once

#include "Flags.h"
#include "FormatMacro.h"

#include <variant>

namespace GnssLogs
{
enum class PositioningSystemMode
{
    Autonomous,
    Differential,
    Estimated,
    ManualInput,
    DataNotValid
};

enum class SolutionStatus
{
    SOL_COMPUTED,
    INSUFFICIENT_OBS,
    NO_CONVERGENCE,
    SINGULARITY,
    COV_TRACE,
    TEST_DIST,
    COLD_START,
    V_H_LIMIT,
    VARIANCE,
    RESIDUALS,
    INTEGRITY_WARNING = 13,
    PENDING           = 18,
    INVALID_FIX,
    UNAUTHORIZED,
    INVALID_RATE = 22
};

enum class PositionOrVelocityType
{
    NONE,
    FIXEDPOS,
    FIXEDHEIGHT,
    DOPPLER_VELOCITY = 9,
    SINGLE           = 16,
    PSRDIFF,
    WAAS,
    PROPAGATED,
    L1_FLOAT     = 32,
    NARROW_FLOAT = 34,
    L1_INT       = 48,
    WIDE_INT,
    NARROW_INT,
    RTK_DIRECT_INS,
    INS_SBAS,
    INS_PSRSP,
    INS_PSRDIFF,
    INS_RTKFLOAT,
    INS_RTKFIXED,
    EXT_CONSTRAINED = 67,
    PPP_CONVERGING,
    PPP,
    OPERATIONAL,
    WARNING,
    OUT_OF_BOUNDS,
    INS_PPP_CONVERGING,
    INS_PPP,
    PPP_BASIC_CONVERGING,
    PPP_BASIC,
    INS_PPP_BASIC_CONVERGING,
    INS_PPP_BASIC
};

enum class GPSAndGLONASSSignalUsedMask
{
    GPSL1     = 0x01,
    GPSL2     = 0x02,
    GPSL5     = 0x04,
    Reserved1 = 0x08,
    GLONASSL1 = 0x10,
    GLONASSL2 = 0x20,
    GLONASSL3 = 0x40,
    Reserved2 = 0x80
};
using GPSAndGLONASSSignalUsedMasks = Flags<GPSAndGLONASSSignalUsedMask>;

enum class GalileoAndBeiDouSignalUsedMask
{
    GalileoE1     = 0x01,
    GalileoE5a    = 0x02,
    GalileoE5b    = 0x04,
    GalileoALTBOC = 0x08,
    BeiDouB1      = 0x10,
    BeiDouB2      = 0x20,
    BeiDouB3      = 0x40,
    GalileoE6     = 0x80
};
using GalileoAndBeiDouSignalUsedMasks = Flags<GalileoAndBeiDouSignalUsedMask>;

enum class PseudorangeIonoCorrection : uint8_t
{
    Unknown,
    KlobucharBroadcast,
    SBASBroadcast,
    MultifrequencyComputed,
    PSRDiffCorrection,
    NovAtelBlendedIonoValue
};

enum class DatumID
{
    WGS84 = 61,
    USER  = 63
};

enum class ClockModelStatus
{
    VALID,
    CONVERGING,
    ITERATING,
    INVALID
};

enum class UTCStatus
{
    INVALID,
    VALID,
    WARNING
};

enum class SatelliteSystem : uint32_t
{
    GPS,
    GLONASS,
    SBAS,
    GALILEO,
    BEIDOU,
    QZSS,
    NAVIC,
    OTHER
};

enum class ObservationStatuses
{
    GOOD,
    BADHEALTH,
    OLDEPHEMERIS,
    ELEVATIONERROR = 6,
    MISCLOSURE,
    NODIFFCORR,
    NOEPHEMERIS,
    INVALIDIODE,
    LOCKEDOUT,
    LOWPOWER,
    OBSL2,
    UNKNOWN = 15,
    NOIONOCORR,
    NOTUSED,
    OBSL1,
    OBSE1,
    OBSL5,
    OBSE5,
    OBSB2,
    OBSB1,
    OBSB3,
    NOSIGNALMATCH,
    SUPPLEMENTARY,
    NA = 99,
    BAD_INTEGRITY,
    LOSSOFLOCK,
    NOAMBIGUITY
};

enum class GPSSignalMask
{
    L1 = 0x01,
    L2 = 0x02,
    L5 = 0x04
};
using GPSSignalMasks = Flags<GPSSignalMask>;

enum class GLONASSSignalMask
{
    L1 = 0x01,
    L2 = 0x02,
    L3 = 0x04
};
using GLONASSSignalMasks = Flags<GLONASSSignalMask>;

enum class GalileoSignalMask
{
    E1     = 0x01,
    E5A    = 0x02,
    E5B    = 0x04,
    ALTBOC = 0x08,
    E6     = 0x10
};
using GalileoSignalMasks = Flags<GalileoSignalMask>;

enum class BeiDouSignalMask
{
    B1I = 0x01,
    B2I = 0x02,
    B3  = 0x04,
    B1C = 0x08,
    B2a = 0x10,
    B2b = 0x20
};
using BeiDouSignalMasks = Flags<BeiDouSignalMask>;

enum class QZSSSignalMask
{
    L1 = 0x01,
    L2 = 0x02,
    L5 = 0x04,
    L6 = 0x08
};
using QZSSSignalMasks = Flags<QZSSSignalMask>;

enum class NavICSignalMask
{
    L5 = 0x04
};
using NavICSignalMasks = Flags<NavICSignalMask>;
using SignalMasks      = std::
    variant<GPSSignalMasks, GLONASSSignalMasks, std::monostate, GalileoSignalMasks, BeiDouSignalMasks, QZSSSignalMasks, NavICSignalMask>;

enum class SignatureStatus
{
    NONE,
    INVALID,
    VALID,
    RESERVED,
    HIGH_SPEED
};

enum class AuthCodeType
{
    STANDARD,
    SIGNATURE,
    EMBEDDED
};

enum class PositionAveragingStatus
{
    OFF,
    INPROGRESS,
    COMPLETE
};

enum class SystemUserdForTiming
{
    GPS,
    GLONASS,
    GALILEO,
    BEIDOU,
    NAVIC,
    AUTO = 99
};

enum class RaimMode
{
    DISABLE,
    USER,
    DEFAULT,
    APPROACH,
    TERMINAL,
    ENROUTE
};

enum class IntegrityStatus
{
    NOT_AVAILABLE,
    PASS,
    FAIL
};

enum class ProtectionLevelStatus
{
    NOT_AVAILABLE,
    PASS,
    ALERT
};

struct ExtendedSolutionStatus
{
    uint8_t flag                                        : 1;
    PseudorangeIonoCorrection pseudorangeIonoCorrection : 3;
    uint8_t rtkAssistActive                             : 1;
    uint8_t antennaWarning                              : 1;
    uint8_t reversed                                    : 1;
    uint8_t includesTerrain                             : 1;
};

struct UTC
{
    uint8_t hh;
    uint8_t mm;
    uint8_t ss;
    uint8_t ssLast;
};

struct Date
{
    uint8_t dd;
    uint8_t mm;
    uint8_t yy;
};

} // namespace GnssLogs

GNSSLOGS_ENUM_DECLARE_FORMATTER(GnssLogs, PositioningSystemMode, Autonomous, Differential, Estimated, ManualInput, DataNotValid)
GNSSLOGS_ENUM_DECLARE_FORMATTER(GnssLogs,
                                SolutionStatus,
                                SOL_COMPUTED,
                                INSUFFICIENT_OBS,
                                NO_CONVERGENCE,
                                SINGULARITY,
                                COV_TRACE,
                                TEST_DIST,
                                COLD_START,
                                V_H_LIMIT,
                                VARIANCE,
                                RESIDUALS,
                                INTEGRITY_WARNING,
                                PENDING,
                                INVALID_FIX,
                                UNAUTHORIZED,
                                INVALID_RATE)
GNSSLOGS_ENUM_DECLARE_FORMATTER(GnssLogs,
                                PositionOrVelocityType,
                                NONE,
                                FIXEDPOS,
                                FIXEDHEIGHT,
                                DOPPLER_VELOCITY,
                                SINGLE,
                                PSRDIFF,
                                WAAS,
                                PROPAGATED,
                                L1_FLOAT,
                                NARROW_FLOAT,
                                L1_INT,
                                WIDE_INT,
                                NARROW_INT,
                                RTK_DIRECT_INS,
                                INS_SBAS,
                                INS_PSRSP,
                                INS_PSRDIFF,
                                INS_RTKFLOAT,
                                INS_RTKFIXED,
                                EXT_CONSTRAINED,
                                PPP_CONVERGING,
                                PPP,
                                OPERATIONAL,
                                WARNING,
                                OUT_OF_BOUNDS,
                                INS_PPP_CONVERGING,
                                INS_PPP,
                                PPP_BASIC_CONVERGING,
                                PPP_BASIC,
                                INS_PPP_BASIC_CONVERGING,
                                INS_PPP_BASIC)
GNSSLOGS_ENUM_DECLARE_FORMATTER(GnssLogs,
                                GPSAndGLONASSSignalUsedMask,
                                GPSL1,
                                GPSL2,
                                GPSL5,
                                Reserved1,
                                GLONASSL1,
                                GLONASSL2,
                                GLONASSL3,
                                Reserved2)
GNSSLOGS_ENUM_DECLARE_FORMATTER(GnssLogs,
                                GalileoAndBeiDouSignalUsedMask,
                                GalileoE1,
                                GalileoE5a,
                                GalileoE5b,
                                GalileoALTBOC,
                                BeiDouB1,
                                BeiDouB2,
                                BeiDouB3,
                                GalileoE6)
GNSSLOGS_ENUM_DECLARE_FORMATTER(GnssLogs,
                                PseudorangeIonoCorrection,
                                Unknown,
                                KlobucharBroadcast,
                                SBASBroadcast,
                                MultifrequencyComputed,
                                PSRDiffCorrection,
                                NovAtelBlendedIonoValue)
GNSSLOGS_ENUM_DECLARE_FORMATTER(GnssLogs, DatumID, WGS84, USER)
GNSSLOGS_ENUM_DECLARE_FORMATTER(GnssLogs, ClockModelStatus, VALID, CONVERGING, ITERATING, INVALID)
GNSSLOGS_ENUM_DECLARE_FORMATTER(GnssLogs, UTCStatus, INVALID, VALID, WARNING)
GNSSLOGS_ENUM_DECLARE_FORMATTER(GnssLogs, SatelliteSystem, GPS, GLONASS, SBAS, GALILEO, BEIDOU, QZSS, NAVIC, OTHER)
GNSSLOGS_ENUM_DECLARE_FORMATTER(GnssLogs,
                                ObservationStatuses,
                                GOOD,
                                BADHEALTH,
                                OLDEPHEMERIS,
                                ELEVATIONERROR,
                                MISCLOSURE,
                                NODIFFCORR,
                                NOEPHEMERIS,
                                INVALIDIODE,
                                LOCKEDOUT,
                                LOWPOWER,
                                OBSL2,
                                UNKNOWN,
                                NOIONOCORR,
                                NOTUSED,
                                OBSL1,
                                OBSE1,
                                OBSL5,
                                OBSE5,
                                OBSB2,
                                OBSB1,
                                OBSB3,
                                NOSIGNALMATCH,
                                SUPPLEMENTARY,
                                NA,
                                BAD_INTEGRITY,
                                LOSSOFLOCK,
                                NOAMBIGUITY)
GNSSLOGS_ENUM_DECLARE_FORMATTER(GnssLogs, GPSSignalMask, L1, L2, L5)
GNSSLOGS_ENUM_DECLARE_FORMATTER(GnssLogs, GLONASSSignalMask, L1, L2, L3)
GNSSLOGS_ENUM_DECLARE_FORMATTER(GnssLogs, GalileoSignalMask, E1, E5A, E5B, ALTBOC, E6)
GNSSLOGS_ENUM_DECLARE_FORMATTER(GnssLogs, BeiDouSignalMask, B1I, B2I, B3, B1C, B2a, B2b)
GNSSLOGS_ENUM_DECLARE_FORMATTER(GnssLogs, QZSSSignalMask, L1, L2, L5, L6)
GNSSLOGS_ENUM_DECLARE_FORMATTER(GnssLogs, NavICSignalMask, L5)
GNSSLOGS_ENUM_DECLARE_FORMATTER(GnssLogs, SignatureStatus, NONE, INVALID, VALID, RESERVED, HIGH_SPEED)
GNSSLOGS_ENUM_DECLARE_FORMATTER(GnssLogs, AuthCodeType, STANDARD, SIGNATURE, EMBEDDED)
GNSSLOGS_ENUM_DECLARE_FORMATTER(GnssLogs, PositionAveragingStatus, OFF, INPROGRESS, COMPLETE)
GNSSLOGS_ENUM_DECLARE_FORMATTER(GnssLogs, SystemUserdForTiming, GPS, GLONASS, GALILEO, BEIDOU, NAVIC, AUTO)
GNSSLOGS_ENUM_DECLARE_FORMATTER(GnssLogs, RaimMode, DISABLE, USER, DEFAULT, APPROACH, TERMINAL, ENROUTE)
GNSSLOGS_ENUM_DECLARE_FORMATTER(GnssLogs, IntegrityStatus, NOT_AVAILABLE, PASS, FAIL)
GNSSLOGS_ENUM_DECLARE_FORMATTER(GnssLogs, ProtectionLevelStatus, NOT_AVAILABLE, PASS, ALERT)

GNSSLOGS_DECLARE_FORMATTER(GnssLogs::UTC)
GNSSLOGS_DECLARE_FORMATTER(GnssLogs::Date)
template<class CharT>
struct std::formatter<GnssLogs::ExtendedSolutionStatus, CharT>
{
    constexpr typename std::basic_format_parse_context<CharT>::iterator parse(std::basic_format_parse_context<CharT>& pc)
    {
        std::basic_string<CharT> str(pc.begin(), pc.end());
        if (pc.begin() == pc.end() || *pc.begin() == '}')
        {
            return pc.end();
        }
        else
        {
            throw std::format_error(std::format("Invalid format arg {}", "GnssLogs::ExtendedSolutionStatus"));
        }
    }
    template<typename OutIterator>
    auto format(const GnssLogs::ExtendedSolutionStatus& t, std::basic_format_context<OutIterator, CharT>& fc) const
    {
        std::format_to(fc.out(), "{} : \n", "GnssLogs::ExtendedSolutionStatus");
        std::format_to(fc.out(), "flag : {}\n", t.flag);
        std::format_to(fc.out(), "pseudorangeIonoCorrection : {}\n", t.pseudorangeIonoCorrection);
        std::format_to(fc.out(), "rtkAssistActive : {}\n", t.rtkAssistActive);
        std::format_to(fc.out(), "antennaWarning : {}\n", t.antennaWarning);
        std::format_to(fc.out(), "reversed : {}\n", t.reversed);
        std::format_to(fc.out(), "includesTerrain : {}\n", t.includesTerrain);
        return fc.out();
    }
};